#include <stdio.h>
#include <stdlib.h>
#include <iterator>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <ctime>
#include <cmath>
#include <limits>
#include <time.h>
#include "IVCalculator.h"

clock_t curt;
class CVSRow
{
public:
  std::string const& operator[](std::size_t index) const
  {
    return m_data[index];
  }

  std::size_t size() const
  {
    return m_data.size();
  }

  void readNextRow(std::istream& str)
  {
    std::string         line;
    std::getline(str,line);

    std::stringstream   lineStream(line);
    std::string         cell;

    m_data.clear();
    while(std::getline(lineStream,cell,','))
      {
        m_data.push_back(cell);
      }
  }

private:
  std::vector<std::string>    m_data;
};


std::istream& operator>>(std::istream& str, CVSRow& data)
{
  data.readNextRow(str);
  return str;
}

void parse_row(option &opt, CVSRow row) {

  opt.strike = atof(row[2].c_str());
  opt.bid = atof(row[4].c_str());
  opt.ask = atof(row[5].c_str());
  opt.year = atoi(row[0].c_str()) + 2000;

  if (row[1] == "Jan")
    opt.month = 1;
  else if (row[1] == "Feb")
    opt.month = 2;
  else if (row[1] == "Mar")
    opt.month = 3;
  else if (row[1] == "Apr")
    opt.month = 4;
  else if (row[1] == "May")
    opt.month = 5;
  else if (row[1] == "Jun")
    opt.month = 6;
  else if (row[1] == "Jul")
    opt.month = 7;
  else if (row[1] == "Aug")
    opt.month = 8;
  else if (row[1] == "Sep")
    opt.month = 9;
  else if (row[1] == "Oct")
    opt.month = 10;
  else if (row[1] == "Nov")
    opt.month = 11;
  else if (row[1] == "Dec")
    opt.month = 12;
  else
    opt.month = 0;

  if (opt.month == 1 || opt.month == 3 || opt.month == 5 ||
      opt.month == 7 || opt.month == 8 || opt.month == 10 || opt.month == 12)
    opt.day = 31;
  else if (opt.month == 2) {
    if (opt.year%4 == 0) {
      opt.day = 29;
    }
    else {
      opt.day = 28;
    }
  }
  else {
    opt.day = 30;
  }
}


// stupid but just for the sake of checking correctness
void  extract_options(std::string symbol, int type, std::vector<option> * options){

  std::string filename;

  if (type == 1){
    filename = "../input/" + symbol + "_call.csv";
  }
  else {
    filename = "../input/" + symbol + "_put.csv";
  }

  std::ifstream file(filename.c_str());

  CVSRow row;
  while(file >> row)
    {
      option opt;
      opt.type = type;
      parse_row(opt, row);
      options->push_back(opt);
    }
}



int main()
{
  std::ifstream file("symbol_list.txt");
  std::string symbol;
  // extracted vector data
  std::vector<option> options;

  // get input data - option chain
  if (file.is_open()) {
    while(!file.eof()){

      getline(file, symbol);
      if (symbol == "") {
        continue;
      }
      extract_options(symbol, 1, &options);
    }
    file.close();
  }else {
    std::cout << "Unable to open file 'symbol_list.txt'\n";
  }
/*
  for(int i = 0; i < options.size(); i++) {
    printf("type : %d, ", options[i].type);
    printf("strike : %f, ", options[i].strike);
    printf("bid : %f, ", options[i].bid);
    printf("ask : %f, ", options[i].ask);
    printf("\n");
  }
*/
  /* manual input - must be changed
   spot은 따로 저장파일 만드거나 risk는 그때 그때 argv로 너주던가~*/
  double spot = 28.69f;
  double risk = 0.0052f;
  int numOptions = options.size();

  time_t t = time(0);
  struct tm * now = localtime(&t);

  double curr_year = now->tm_year + 1900;
  double curr_month = now->tm_mon + 1;
  double curr_day = now->tm_mday;


  // generate cuda workers
  IVCalculator * IVC;
  IVC = new IVCalculator();
  int i = 0;
  clock_t curt = clock();
  for(int i = 0; i < 1000; i++) {
      IVC->loadOptionData(&options, i*(numOptions/1000), (i+1)*(numOptions/1000),numOptions, spot, risk, curr_year, curr_month, curr_day);
      IVC->setup();
      IVC->calculateIV();
  }

  // retrieve the result
  double * resultIV = IVC->getResultIV();
  double * resultPR = IVC->getResultPR();

  printf("numOptions in main : %d\n", numOptions);

  // result check
  for(int i = 0; i < numOptions; i++)
    {
//      printf("Ask : %f | ", options[i].ask);
//      printf("Bid : %f \n", options[i].bid);
      //printf("IV : %f | ", resultIV[i]);
      //printf("PR : %f\n", resultPR[i]);
    }

  delete IVC;
  printf("%f\n",(double)(clock() - curt)/CLOCKS_PER_SEC);
}
